#include <iostream>
#include <pthread.h>
#include <vector>
#include <semaphore.h>
#include <cassert>
using namespace std;

static const int gCap = 10;

template <class T>
class RingQueue
{
private:
    void P(sem_t &_Sem) // 等待
    {
        int n = sem_wait(&_Sem);
        assert(0 == n);
        (void)n;
    }

    void V(sem_t &_Sem)
    {
        int n = sem_post(&_Sem);
        assert(0 == n);
        (void)n;
    }

public:
    RingQueue(const int &cap = gCap)
        : _queue(cap), _cap(cap), _productorIndex(0), _consumerIndex(0)
    {
        // 对信号量进行初始化 不共享
        int n = sem_init(&_spaceSem, 0, _cap);
        assert(0 == n);
        (void)n;

        n = sem_init(&_dataSem, 0, 0);
        assert(0 == n);
        (void)n;

        pthread_mutex_init(&_pmutex, nullptr);
        pthread_mutex_init(&_cmutex, nullptr);
    }

    void Push(const T &in)
    {
        P(_spaceSem);//先申请信号量，再加锁，高效
        pthread_mutex_lock(&_pmutex);
        _queue[_productorIndex++] = in;
        _productorIndex %= _cap;
        pthread_mutex_unlock(&_pmutex);
        V(_dataSem);
    }

    void Pop(T *out) // 输出型参数
    {
        // 对资源进行P操作
        P(_dataSem);
        pthread_mutex_lock(&_cmutex);
        *out = _queue[_consumerIndex++];
        _consumerIndex %= _cap;
        pthread_mutex_unlock(&_cmutex);
        V(_spaceSem);
    }

    ~RingQueue()
    {
        sem_destroy(&_spaceSem);
        sem_destroy(&_dataSem);

        pthread_mutex_destroy(&_pmutex);
        pthread_mutex_destroy(&_cmutex);
    }

private:
    vector<T> _queue;
    int _cap;                // 环形队列的最大容量
    sem_t _spaceSem;         // 生产者的空间资源
    sem_t _dataSem;          // 消费者的数据资源
    int _productorIndex;     // 生产者的下标
    int _consumerIndex;      // 消费者的下标
    pthread_mutex_t _pmutex; // 生产者锁
    pthread_mutex_t _cmutex; // 消费者锁
};